// FileUpload.cpp: implementation of the FileUpload class.
//
//////////////////////////////////////////////////////////////////////

#include "FileUpload.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

FileUpload::FileUpload()
{
	Logger::writeToLog (T("ctor"));
	formPost		= NULL;
	lastFormPost	= NULL;
	uploadListeners	= 2;
	CURLcode ret;

	curl_global_init(CURL_GLOBAL_WIN32);
	
	curl			= curl_easy_init();

	if (!curl)
	{
		throw (-1);
	}

	if (ret = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE))
	{
		currentError = curl_easy_strerror(ret);
		throw (-1);
	}
	if (ret = curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallback))
	{
		currentError = curl_easy_strerror(ret);
		throw (-1);
	}
	
	if (ret = curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this))
	{
		currentError = curl_easy_strerror(ret);
		throw (-1);
	}

	if (ret = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction))
	{
		currentError = curl_easy_strerror(ret);
		throw (-1);
	}
}

FileUpload::~FileUpload()
{
	cleanup();
}

void FileUpload::cleanup()
{
	curl_easy_cleanup (curl);
}

bool FileUpload::setUrl (String url)
{
	if (curl)
	{
		CURLcode ret = curl_easy_setopt(curl, CURLOPT_URL, url.toUTF8());
		if (ret)
		{
			currentError = curl_easy_strerror(ret);
			return (false);
		}

		Logger::writeToLog (T("setUrl: success"));

		return (true);
	}
	else
	{
		return (false);
	}
}

bool FileUpload::setFormField (String formVarName, String formVarValue)
{
	CURLFORMcode ret = curl_formadd (&formPost, &lastFormPost, CURLFORM_COPYNAME, formVarName.toUTF8(), CURLFORM_COPYCONTENTS, formVarValue.toUTF8(), CURLFORM_END);
	if (ret)
	{
		return (false);
	}
	else
	{
		return (true);
	}
}

bool FileUpload::setFormField (String formVarName, File formVarValue)
{
	CURLFORMcode ret = curl_formadd(&formPost, &lastFormPost, CURLFORM_COPYNAME, formVarName.toUTF8(), CURLFORM_FILE, formVarValue.getFullPathName().toUTF8(), CURLFORM_END);
	if (ret)
	{
		return (false);
	}
	else
	{
		return (true);
	}
}

bool FileUpload::post ()
{
	CURLcode ret;
	
	if (formPost)
	{
		ret = curl_easy_setopt(curl, CURLOPT_HTTPPOST, formPost);

		if (ret)
		{
			currentError = curl_easy_strerror(ret);
			return (false);
		}
	}

	ret = curl_easy_perform(curl);

	if (ret)
	{		
		currentError = curl_easy_strerror(ret);
		return (false);
	}
	else
	{
		return (true);
	}
}

void FileUpload::addUploadListener (FileUploadListener *newListener)
{
    jassert (newListener != 0);
    jassert (! uploadListeners.contains (newListener));

    if (newListener != 0)
        uploadListeners.add (newListener);
}

int FileUpload::progressCallback (void* data, double dltotal, double dlnow, double ultotal, double ulnow)
{
	FileUpload *ptr = (FileUpload *)data;
	
    for (int i = ptr->uploadListeners.size(); --i >= 0;)
    {
        FileUploadListener* const bl = (FileUploadListener*) ptr->uploadListeners[i];

        if (bl != 0)
        {
            return (bl->uploadProgressCallback (dltotal,dlnow,ultotal,ulnow));
        }
    }

	return (0);
}

int FileUpload::writeFunction (void *ptr, size_t size, size_t nmemb, void *stream)
{
	return (int)nmemb; 
}

String FileUpload::getLastError()
{
	return (currentError);
}

bool FileUpload::setProxy (String url)
{
	if (curl)
	{
		CURLcode ret = curl_easy_setopt(curl, CURLOPT_PROXY, url.toUTF8());
		if (ret)
		{
			currentError = curl_easy_strerror(ret);
			return (false);
		}

		Logger::writeToLog (T("setProxy: success"));

		return (true);
	}
	else
	{
		return (false);
	}
}

bool FileUpload::setProxyType (int t)
{
	if (curl)
	{
		CURLcode ret = curl_easy_setopt(curl, CURLOPT_PROXYTYPE, t);
		
		if (ret)
		{
			currentError = curl_easy_strerror(ret);
			return (false);
		}

		Logger::writeToLog (T("setProxyType: success"));

		return (true);
	}
	else
	{
		return (false);
	}
}